package com.inspur.edp.cef.designtime.api.json.element;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection;
import com.inspur.edp.cef.designtime.api.collection.GspEnumValueCollection;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.element.ElementDefaultVauleType;
import com.inspur.edp.cef.designtime.api.element.EnumIndexType;
import com.inspur.edp.cef.designtime.api.element.FieldCollectionType;
import com.inspur.edp.cef.designtime.api.element.FieldRepoExtendConfigInfo;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementDataType;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.designtime.api.entity.CustomizationInfo;
import com.inspur.edp.cef.designtime.api.entity.DynamicPropSetInfo;
import com.inspur.edp.cef.designtime.api.entity.GspCommonField;
import com.inspur.edp.cef.designtime.api.entity.MappingInfo;
import com.inspur.edp.cef.designtime.api.entity.MappingRelation;
import com.inspur.edp.cef.designtime.api.entity.MdRefInfo;
import com.inspur.edp.cef.designtime.api.exceptions.CommonEntityErrorCodeEnum;
import com.inspur.edp.cef.designtime.api.exceptions.CommonEntityException;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import com.inspur.edp.cef.designtime.api.json.SerializerUtils;

import java.io.IOException;
import java.util.ArrayList;

import static com.fasterxml.jackson.core.JsonToken.FIELD_NAME;

/**
 * The Json Parser Of CefField
 *
 * @ClassName: CefFieldDeserializer
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
public abstract class CefFieldDeserializer extends JsonDeserializer<IGspCommonField> {

  @Override
  public IGspCommonField deserialize(JsonParser jsonParser,
      DeserializationContext deserializationContext) {
    return deserializeCommonField(jsonParser);
  }

  public IGspCommonField deserializeCommonField(JsonParser jsonParser) {
    GspCommonField field = CreateField();
    beforeCefElementDeserializer(field);
    field.setIsRefElement(false);
    field.setIsRef(false);
    field.setLength(0);
    field.setPrecision(0);
    field.setIsRequire(false);
    field.setIsMultiLanguage(false);
    field.setIsUdt(false);
    field.setIsFromAssoUdt(false);
    field.setIsFromAssoUdt(false);
    field.setIsVirtual(false);
    field.setMappingRelation(new MappingRelation());
    field.setContainEnumValues(new GspEnumValueCollection());
    field.setUdtPkgName("");
    field.setUdtID("");
    field.setRefBusinessFieldId("");
    field.setRefBusinessFieldName("");
    field.setUdtName("");
    field.setBeLabel(new ArrayList<>());
    field.setBizTagIds(new ArrayList<>());
    MdRefInfo info = new MdRefInfo();
    info.setId("");
    info.setName("");
    info.setPkgName("");
    DynamicPropSetInfo dyinfo = new DynamicPropSetInfo();
    dyinfo.setDynamicPropRepositoryComp(info);
    dyinfo.setDynamicPropSerializerComp(info);
    field.setDynamicPropSetInfo(dyinfo);
//    GspAssociationCollection collection = new GspAssociationCollection();
//    field.setChildAssociations(collection);

    SerializerUtils.readStartObject(jsonParser);
    while (jsonParser.getCurrentToken() == FIELD_NAME) {
      String propName = SerializerUtils.readPropertyName(jsonParser);
      readPropertyValue(field, propName, jsonParser);
    }
    SerializerUtils.readEndObject(jsonParser);

    return field;
  }

  private void readPropertyValue(GspCommonField field, String propName, JsonParser jsonParser) {
    switch (propName) {
      case CefNames.ID:
        field.setID(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.Code:
        field.setCode(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.Name:
        field.setName(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.LabelID:
        field.setLabelID(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.BeLabel:
        field.setBeLabel(SerializerUtils.readStringArray(jsonParser));
        break;
      case CefNames.BizTagIds:
        field.setBizTagIds(SerializerUtils.readStringArray(jsonParser));
        break;
      case CefNames.MDataType:
        field.setMDataType(SerializerUtils
            .readPropertyValue_Enum(jsonParser, GspElementDataType.class,
                GspElementDataType.values()));
        break;
      case CefNames.DefaultValue:
        field.setDefaultValue(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.DefaultVauleType:
      case CefNames.DefaultValueType:
        field.setDefaultValueType(SerializerUtils
            .readPropertyValue_Enum(jsonParser, ElementDefaultVauleType.class,
                ElementDefaultVauleType.values()));
        break;
      case CefNames.DisplayDefaultValue:
        field.setDisplayDefaultValue(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.ChangedProperties:
        field.setChangedProperties(SerializerUtils.readStringArray(jsonParser));
        break;
      case CefNames.Length:
        field.setLength(SerializerUtils.readPropertyValue_Integer(jsonParser));
        break;
      case CefNames.Precision:
        field.setPrecision(SerializerUtils.readPropertyValue_Integer(jsonParser));
        break;
      case CefNames.ObjectType:
        field.setObjectType(SerializerUtils
            .readPropertyValue_Enum(jsonParser, GspElementObjectType.class,
                GspElementObjectType.values()));
        break;
      case CefNames.ChildAssociations:
        readChildAssociations(jsonParser, field);
        break;
      case CefNames.ContainEnumValues:
        readContainEnumValues(jsonParser, field);
        break;
      case CefNames.IsVirtual:
        field.setIsVirtual(SerializerUtils.readPropertyValue_boolean(jsonParser));
        break;
      case CefNames.IsRequire:
        field.setIsRequire(SerializerUtils.readPropertyValue_boolean(jsonParser));
        break;
      case CefNames.IsRefElement:
        field.setIsRefElement(SerializerUtils.readPropertyValue_boolean(jsonParser));
        break;
      case CefNames.IsMultiLanguage:
        field.setIsMultiLanguage(SerializerUtils.readPropertyValue_boolean(jsonParser));
        break;
      case CefNames.IsRef:
        field.setIsRef(SerializerUtils.readPropertyValue_boolean(jsonParser));
        break;
      case CefNames.RefElementID:
        field.setRefElementId(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.IsUdt:
        field.setIsUdt(SerializerUtils.readPropertyValue_boolean(jsonParser));
        break;
      case CefNames.UdtPkgName:
        field.setUdtPkgName(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.UdtID:
        field.setUdtID(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.RefBusinessFieldId:
        field.setRefBusinessFieldId(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.RefBusinessFieldName:
        field.setRefBusinessFieldName(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.UdtName:
        field.setUdtName(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.MappingRelation:
        readMappingRelation(jsonParser, field);
        break;
      case CefNames.ChildElements:
        readChildElements(jsonParser, field);
        break;
      case CefNames.CollectionType:
        field.setCollectionType(SerializerUtils
            .readPropertyValue_Enum(jsonParser, FieldCollectionType.class,
                FieldCollectionType.values()));
        break;
      case CefNames.IsFromAssoUdt:
        field.setIsFromAssoUdt(SerializerUtils.readPropertyValue_boolean(jsonParser));
        break;
      case CefNames.I18nResourceInfoPrefix:
        field.setI18nResourceInfoPrefix(SerializerUtils.readPropertyValue_String(jsonParser));
        break;
      case CefNames.CustomizationInfo:
        field.setCustomizationInfo(
            SerializerUtils.readPropertyValue_Object(CustomizationInfo.class, jsonParser));
        try {
          jsonParser.nextToken();
        } catch (IOException e) {
            throw CommonEntityException.createException(CommonEntityErrorCodeEnum.GSP_BEMODEL_JSON_0002, e, "GspCommonDataTypeDeserializer", propName);
        }
        break;
      case CefNames.DynamicPropSetInfo:
        readDynamicPropSetInfo(jsonParser, field);
        break;
      case CefNames.EnumIndexType:
        field.setEnumIndexType(SerializerUtils.readPropertyValue_Enum(jsonParser, EnumIndexType.class, EnumIndexType.values()));
        break;
      case CefNames.EnableRtrim:
        field.setEnableRtrim(SerializerUtils.readPropertyValue_boolean(jsonParser));
        break;
      case CefNames.IsBigNumber:
        field.setIsBigNumber(SerializerUtils.readPropertyValue_boolean(jsonParser));
        break;
      case CefNames.ExtendInfo:
        field.setExtendInfo(SerializerUtils.readPropertyValue_Map(jsonParser));
        break;
      case CefNames.SelectFieldRepoExtend:
        field.setSelectFieldRepoConfig(
                SerializerUtils.readPropertyValue_Object(FieldRepoExtendConfigInfo.class, jsonParser));
        try {
          jsonParser.nextToken();
        } catch (IOException e) {
          throw CommonEntityException.createException(CommonEntityErrorCodeEnum.GSP_BEMODEL_JSON_0002, e, "CefFieldDeserializer", propName);
        }
        break;
      default:
        if (!readExtendFieldProperty(field, propName, jsonParser)) {
          throw CommonEntityException.createException(CommonEntityErrorCodeEnum.GSP_BEMODEL_COMMON_ENTITY_0006, "CefFieldDeserializer", propName);
        }
    }
  }

  protected void readDynamicPropSetInfo(JsonParser jsonParser, GspCommonField field) {
    JsonDeserializer<DynamicPropSetInfo> deserializer = new DynamicPropSetInfoDeserializer();
    try {
      DynamicPropSetInfo value = deserializer.deserialize(jsonParser, null);
      field.setDynamicPropSetInfo(value);
    } catch (IOException e) {
      throw CommonEntityException.createException(CommonEntityErrorCodeEnum.GSP_BEMODEL_JSON_0001, e, "DynamicPropSetInfo");
    }
  }

  protected void readMappingRelation(JsonParser jsonParser, GspCommonField field) {
    MappingRelation mappingInfos = new MappingRelation();
    ArrayList<MappingInfo> list = new ArrayList<MappingInfo>();
    JsonDeserializer<MappingInfo> deserializer = new MappingInfoDeserializer();
    SerializerUtils.readArray(jsonParser, deserializer, list);
    for (MappingInfo info : list) {
      mappingInfos.add(info);
    }
    field.setMappingRelation(mappingInfos);
  }

  protected void readChildElements(JsonParser jsonParser, GspCommonField field) {
    GspFieldCollection collection = CreateFieldCollection();
    SerializerUtils.readArray(jsonParser, this, collection);
    field.setChildElements(collection);
  }

  protected void readContainEnumValues(JsonParser jsonParser, GspCommonField field) {
    GspEnumValueCollection collection = new GspEnumValueCollection();
    GspEnumValueDeserializer deserializer = new GspEnumValueDeserializer();
    SerializerUtils.readArray(jsonParser, deserializer, collection);
    field.setContainEnumValues(collection);
  }

  private void readChildAssociations(JsonParser jsonParser, GspCommonField field) {
    GspAssociationCollection collection = CreateGspAssoCollection();
    GspAssociationDeserializer deserializer = CreateGspAssoDeserializer();
    SerializerUtils.readArray(jsonParser, deserializer, collection);
    handleChildAssociations(collection, field);
    field.setChildAssociations(collection);
  }

  private void handleChildAssociations(GspAssociationCollection associations,
      GspCommonField field) {
    for (GspAssociation association : associations) {
      association.setBelongElement(field);
      if(association.getI18nResourceInfoPrefix()==null||"".equals(association.getI18nResourceInfoPrefix()))
        association.setI18nResourceInfoPrefix(field.getI18nResourceInfoPrefix());
    }

  }
  protected abstract void beforeCefElementDeserializer(GspCommonField item);

  protected abstract GspFieldCollection CreateFieldCollection();

  protected abstract GspCommonField CreateField();

  protected GspAssociationCollection CreateGspAssoCollection() {
    return new GspAssociationCollection();
  }

  protected GspAssociationDeserializer CreateGspAssoDeserializer() {
    return new GspAssociationDeserializer(this);
  }

  protected boolean readExtendFieldProperty(GspCommonField field, String propName,
      JsonParser jsonParser) {
    return false;
  }
}
